home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Light ROM 1
/
LIGHT-ROM 1 (Amiga Library Services)(1994).iso
/
ffdisks
/
d939.lha
/
ExtraCmds
/
source_etc.lha
/
src
/
Concat.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-22
|
10KB
|
407 lines
/* --------------------------------- -------
* |\ | | | | | |.| | \| |/ /|\ |||||||
* | | | |/ | |\ |/ |/| |\ |/ | ? ---+--- =<
* | | | | | | | | | | | \qqqqqqqqq/
* --------------------------------- ~~~~~~~~~~~~~~~~
* Concat - Concatenate and print files. AmigaDOS equivalent of UNIX cat.
* Copyright (C) 1992, 1993 Torsten Poulin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* The author can be contacted by s-mail at
* Torsten Poulin
* Banebrinken 99, 2, 77
* DK-2400 Copenhagen NV
* DENMARK
*
* $Id: Concat.c,v 37.12 93/03/30 12:58:19 Torsten Rel $
* $Log: Concat.c,v $
* Revision 37.12 93/03/30 12:58:19 Torsten
* Added explicit check for read errors to fastcat().
*
* Revision 37.11 93/03/26 11:11:53 Torsten
* Now uses another copying algorithm if the VISIBLE switch is not
* specified and the destination is not a virtual terminal.
* An ad hoc test showed a twentyfold speed increase.
* Removed the QUIET switch as it wasn't used anyway ;-).
*
* Revision 37.10 93/03/01 12:40:46 Torsten
* Changed all occurrences of "struct DosBase *" to "struct DosLibrary *"
*
* Revision 37.9 93/02/24 00:21:33 Torsten
* Bug fix: called FreeArgs() too soon.
*
* Revision 37.8 93/02/23 22:40:36 Torsten
* Now it only stores filenames in a list if the sort switch is given.
* The entrypoint function has been restructured a bit to get rid of
* the gotos.
*
* Revision 37.7 93/02/22 18:15:42 Torsten
* Changed to be linked with the support library
*
* Revision 37.6 93/02/19 18:00:14 Torsten
* Rewritten almost from scratch.
* UNBUF switch removed.
*
* Revision 37.5 93/02/18 15:24:25 Torsten
* Removed explicit utility.library/Stricmp() pragma and prototype.
* Replaced AllocMem()/FreeMem() pair with AllocVec()/FreeVec().
*
* Revision 37.4 93/02/11 22:47:48 Torsten
* Source reformatted with GNU indent.
* exec.library/SetSignal() replaced by dos.library/CheckSignal().
*
* Revision 37.3 93/02/07 11:41:37 Torsten
* Updated the copyright tag.
*
* Revision 37.2 93/02/05 11:36:10 Torsten
* checked in with -k by Torsten at 93.02.05.11.36.10.
*
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/lists.h>
#include <exec/nodes.h>
#include <dos/dos.h>
#include <dos/dosasl.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/utility_protos.h>
#ifdef __SASC
#include <pragmas/dos_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/utility_pragmas.h>
#endif
#include <string.h>
#include "tastlib.h"
#include "concat_rev.h"
#define PROGNAME "Concat"
#define TEMPLATE "FILE=FROM/M,AS=TO/K,SORT/S,VISIBLE/S,TABS/S,EOL/S"
#define OPT_FROM 0
#define OPT_TO 1
#define OPT_SORT 2
#define OPT_VISIBLE 3
#define OPT_TABS 4
#define OPT_EOL 5
#define CONCATBUFSIZE 102400L
typedef struct Global {
struct DosLibrary *DOSBase;
struct Library *UtilityBase;
struct List *list;
BPTR output;
BOOL visible;
BOOL tabs;
BOOL eol;
LONG (*concat)(UBYTE *filename, struct Global *global);
UBYTE *buffer;
LONG bufsize;
} Global;
typedef struct {
struct Node nn_Node;
UBYTE nn_filename[MAXNAMELEN+1];
} NameNode;
LONG initlist(Global *global);
VOID freelist(Global *global);
LONG insert(UBYTE *filename, Global *global);
LONG concatall(Global *global);
LONG concat(UBYTE *filename, Global *global);
LONG fastcat(UBYTE *filename, Global *global);
APTR allocBufferVec(LONG *bufsize, Global *global);
char const versionID[] = VERSTAG;
char const copyright[] = "$COPYRIGHT:©1992,1993 Torsten Poulin$";
LONG entrypoint(VOID)
{
struct DosLibrary *DOSBase;
struct RDArgs *args;
Global *global;
LONG arg[6];
LONG rc = RETURN_OK;
if (!(DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37L)))
return RETURN_FAIL;
if (!(global = AllocVec(sizeof(Global), MEMF_CLEAR)))
{
PrintFault(ERROR_NO_FREE_STORE, PROGNAME);
rc = RETURN_FAIL;
}
else
{
global->DOSBase = DOSBase;
if (!(global->UtilityBase = OpenLibrary("utility.library", 37L)))
rc = RETURN_FAIL;
else
{
arg[OPT_FROM] = arg[OPT_TO] = arg[OPT_SORT] =
arg[OPT_VISIBLE] = arg[OPT_TABS] = arg[OPT_EOL] = 0L;
if (!(args = ReadArgs(TEMPLATE, arg, NULL)))
{
printerror(PROGNAME, global);
rc = RETURN_ERROR;
}
else
{
global->visible = (BOOL) arg[OPT_VISIBLE];
global->tabs = (BOOL) arg[OPT_TABS];
global->eol = (BOOL) arg[OPT_EOL];
if (!arg[OPT_TO])
global->output = Output();
else if (!(global->output = Open((UBYTE *) arg[OPT_TO],
MODE_NEWFILE)))
{
PutStr("Cannot open ");
PutStr((UBYTE *) arg[OPT_TO]);
PutStr("\n");
rc = RETURN_ERROR;
}
if (global->output)
{
global->concat = concat;
if (!global->visible && !global->eol && !global->tabs &&
!IsInteractive(global->output))
{
/* If we can't get the buffer, we simply use the slower
* method.
*/
global->bufsize = CONCATBUFSIZE;
if (global->buffer = allocBufferVec(&global->bufsize, global))
global->concat = fastcat;
}
if (!arg[OPT_FROM])
rc = global->concat(NULL, global);
else if (!arg[OPT_SORT])
rc = foreach((UBYTE **) arg[OPT_FROM], global->concat, global);
else if ((rc = initlist(global)) != ERROR_NO_FREE_STORE)
{
if (!(rc = foreach((UBYTE **) arg[OPT_FROM], insert, global)))
rc = concatall(global);
freelist(global);
}
if (arg[OPT_TO])
Close(global->output);
if (global->buffer)
FreeVec(global->buffer);
}
FreeArgs(args);
if (rc == ERROR_BREAK)
{
PrintFault(ERROR_BREAK, NULL);
rc = RETURN_WARN;
}
else if (rc == ERROR_NO_FREE_STORE)
{
PrintFault(ERROR_NO_FREE_STORE, PROGNAME);
rc = RETURN_FAIL;
}
else if (rc != RETURN_OK)
printerror(PROGNAME, global);
}
CloseLibrary(global->UtilityBase);
}
FreeVec(global);
}
CloseLibrary((struct Library *) DOSBase);
return rc;
}
LONG initlist(Global *global)
{
if (!(global->list = AllocVec(sizeof(struct List), MEMF_CLEAR)))
return ERROR_NO_FREE_STORE;
/* Initialize list header */
global->list->lh_Head = (struct Node *) &global->list->lh_Tail;
global->list->lh_Tail = 0;
global->list->lh_TailPred = (struct Node *) &global->list->lh_Head;
return RETURN_OK;
}
VOID freelist(Global *global)
{
NameNode *worknode;
NameNode *nextnode;
worknode = (NameNode *) (global->list->lh_Head);
while (nextnode = (NameNode *) (worknode->nn_Node.ln_Succ))
{
FreeVec(worknode);
worknode = nextnode;
}
FreeVec(global->list);
}
LONG insert(UBYTE *filename, Global *global)
{
struct Library *UtilityBase = global->UtilityBase;
NameNode *namenode;
struct Node *node;
if (!(namenode = AllocVec(sizeof(NameNode), MEMF_CLEAR)))
return ERROR_NO_FREE_STORE;
else
{
strcpy(namenode->nn_filename, filename);
namenode->nn_Node.ln_Name = namenode->nn_filename;
if (global->list->lh_TailPred == (struct Node *) global->list)
AddHead(global->list, (struct Node *) namenode);
else
{
for (node=global->list->lh_Head; node->ln_Succ; node=node->ln_Succ)
if (Stricmp(node->ln_Name, filename) >= 0)
break;
if (node->ln_Succ)
Insert(global->list, (struct Node *) namenode, node->ln_Pred);
else
AddTail(global->list, (struct Node *) namenode);
}
return RETURN_OK;
}
}
LONG concatall(Global *global)
{
struct Node *node;
LONG rc = RETURN_OK;
if (global->list->lh_TailPred != (struct Node *) global->list)
for (node = global->list->lh_Head; node->ln_Succ; node = node->ln_Succ)
if ((rc = global->concat(node->ln_Name, global)) == ERROR_BREAK)
break;
return rc;
}
LONG concat(UBYTE *filename, Global *global)
{
struct DosLibrary *DOSBase = global->DOSBase;
register UBYTE breakcheck = 0;
BPTR input;
LONG c;
if (!filename)
input = Input();
else if (!(input = Open(filename, MODE_OLDFILE)))
{
PutStr("Cannot open ");
printerror(filename, global);
return RETURN_WARN;
}
while ((c = FGetC(input)) != -1)
{
if (global->visible)
{
if (global->eol && c == '\n')
FPutC(global->output, '$');
else if (global->tabs && c == '\t')
{
FPutC(global->output, '^');
c = 'I';
}
else if (c >= 0x80)
{
FPutC(global->output, 'M');
FPutC(global->output, '-');
c &= 0x7f;
}
if ((c < ' ' && c != '\t' && c != '\n') || c == 0x7F)
{
FPutC(global->output, '^');
if (c == 0x7F)
c = '?';
else
c += 'A' - 1;
}
}
FPutC(global->output, c);
if (!(breakcheck -= 4) && CheckSignal(SIGBREAKF_CTRL_C))
{
if (filename)
Close(input);
return ERROR_BREAK;
}
}
if (filename)
Close(input);
return RETURN_OK;
}
LONG fastcat(UBYTE *filename, Global *global)
{
struct DosLibrary *DOSBase = global->DOSBase;
BPTR input;
LONG count, actual;
if (!filename)
input = Input();
else if (!(input = Open(filename, MODE_OLDFILE)))
{
PutStr("Cannot open ");
printerror(filename, global);
return RETURN_WARN;
}
count = 1;
while ((actual = Read(input,global->buffer,global->bufsize))>0 && count>0)
{
count = Write(global->output, global->buffer, actual);
if (CheckSignal(SIGBREAKF_CTRL_C))
{
if (filename)
Close(input);
return ERROR_BREAK;
}
}
if (filename)
Close(input);
return RETURN_OK;
}
APTR allocBufferVec(LONG *bufsize, Global *global)
{
APTR buffer;
for (; *bufsize > 256L; *bufsize /= 2)
if (buffer = AllocVec(*bufsize, MEMF_CLEAR))
return buffer;
return NULL;
}